#include <clusnet/base/DynamicBuffer.h>
#include <gtest/gtest.h>

#include <string>

using namespace clusnet::base;

TEST(DynamicBuffer, Test_append)
{
    DynamicBuffer buffer(16);
    buffer.append("hello", 5);
    ASSERT_EQ(buffer.toString(), "hello");
    ASSERT_EQ(buffer.length(), 5);
    buffer.append("hello", 4);
    ASSERT_EQ(buffer.toString(), "hellohell");
    buffer.append("hello", 0);
    ASSERT_EQ(buffer.toString(), "hellohell");
    ASSERT_EQ(buffer.length(), 9);
}

TEST(DynamicBuffer, Test_appendDouble)
{
    DynamicBuffer buffer;
    buffer.appendDouble(0.0);
    ASSERT_EQ(buffer.toString(), "0");
    buffer.reset();

    buffer.appendDouble(1.0f);
    ASSERT_EQ(buffer.toString(), "1");
    buffer.reset();

    buffer.appendDouble(0.1);
    ASSERT_EQ(buffer.toString(), "0.1");
    buffer.appendDouble(0.05);
    buffer.appendDouble(0.15);
    ASSERT_EQ(buffer.toString(), "0.10.050.15");
    buffer.reset();

    buffer.appendDouble(1.23456789);
    buffer.appendDouble(1.234567);
    buffer.appendDouble(-123.456);
    ASSERT_EQ(buffer.toString(), "1.234567891.234567-123.456");
    buffer.reset();
}

TEST(DynamicBuffer, Test_appendHex)
{
    DynamicBuffer buffer;
    buffer.appendHex(0);
    ASSERT_EQ(buffer.toString(), "0x0");
    buffer.reset();

    buffer.appendHex(8888);
    ASSERT_EQ(buffer.toString(), "0x22B8");
    buffer.reset();
}

TEST(DynamicBuffer, Test_appendInteger)
{
    DynamicBuffer buffer;
    buffer.appendInteger(-2147483647);
    buffer.appendInteger<int>(-2147483647 - 1);
    ASSERT_EQ(buffer.toString(), "-2147483647-2147483648");

    buffer.appendInteger(' ');
    buffer.appendInteger(2147483647);
    ASSERT_EQ(buffer.toString(), "-2147483647-2147483648322147483647");
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<int16_t>::min());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<int16_t>::min()));
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<int16_t>::max());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<int16_t>::max()));
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<uint16_t>::min());
    buffer.appendInteger(std::numeric_limits<uint16_t>::max());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<uint16_t>::min()) + std::to_string(std::numeric_limits<uint16_t>::max()));
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<int32_t>::min());
    buffer.appendInteger(std::numeric_limits<int32_t>::max());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<int32_t>::min()) + std::to_string(std::numeric_limits<int32_t>::max()));
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<uint32_t>::min());
    buffer.appendInteger(std::numeric_limits<uint32_t>::max());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<uint32_t>::min()) + std::to_string(std::numeric_limits<uint32_t>::max()));
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<int64_t>::min());
    buffer.appendInteger(std::numeric_limits<int64_t>::max());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<int64_t>::min()) + std::to_string(std::numeric_limits<int64_t>::max()));
    buffer.reset();

    buffer.appendInteger(std::numeric_limits<uint64_t>::min());
    buffer.appendInteger(std::numeric_limits<uint64_t>::max());
    ASSERT_EQ(buffer.toString(), std::to_string(std::numeric_limits<uint64_t>::min()) + std::to_string(std::numeric_limits<uint64_t>::max()));
    buffer.reset();

    buffer.appendInteger(true);
    buffer.appendInteger(false);
    ASSERT_EQ(buffer.toString(), "10");
    buffer.reset();
}

class DynamicBufferTest : public testing::Test
{
    public:
        DynamicBufferTest() = default;
        virtual ~DynamicBufferTest() = default;
        DynamicBufferTest(const DynamicBufferTest&) = delete;
        DynamicBufferTest& operator= (const DynamicBufferTest&) = delete;

        virtual void SetUp() override
        {
            buffer.append("hello", 5);
        }

    protected:
        DynamicBuffer   buffer;
};

TEST_F(DynamicBufferTest, Test_bzero)
{
    buffer.bzero();
    std::string zero(5, '\0');
    ASSERT_EQ(buffer.length(), 5);
    ASSERT_EQ(buffer.toString(), zero);
}

TEST_F(DynamicBufferTest, Test_reset)
{
    buffer.reset();
    ASSERT_EQ(buffer.length(), 0);
    ASSERT_TRUE(buffer.toString().empty());
}

TEST_F(DynamicBufferTest, Test_copyConstruct)
{
    DynamicBuffer leftCopyBuffer(buffer);
    ASSERT_EQ(buffer.length(), leftCopyBuffer.length());
    ASSERT_EQ(buffer.toString(), leftCopyBuffer.toString());

    DynamicBuffer rightCopyBuffer(std::move(leftCopyBuffer));
    ASSERT_EQ(buffer.length(), rightCopyBuffer.length());
    ASSERT_EQ(buffer.toString(), rightCopyBuffer.toString());
}

TEST_F(DynamicBufferTest, Test_assign)
{
    DynamicBuffer leftAssignBuffer;
    leftAssignBuffer = buffer;
    ASSERT_EQ(buffer.length(), leftAssignBuffer.length());
    ASSERT_EQ(buffer.toString(), leftAssignBuffer.toString());

    DynamicBuffer rightAssignBuffer;
    rightAssignBuffer = std::move(leftAssignBuffer);
    ASSERT_EQ(buffer.length(), rightAssignBuffer.length());
    ASSERT_EQ(buffer.toString(), rightAssignBuffer.toString());
}

int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
